// Copyright Epic Games, Inc. All Rights Reserved.

#include "Accolades/LyraAccoladeHostWidget.h"  // 包含荣誉宿主控件头文件

#include "DataRegistrySubsystem.h"  // 包含数据注册表子系统
#include "LyraLogChannels.h"  // 包含Lyra日志通道
#include "Messages/LyraNotificationMessage.h"  // 包含Lyra通知消息
#include "Sound/SoundBase.h"  // 包含声音基类
#include "TimerManager.h"  // 包含计时器管理器

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraAccoladeHostWidget)  // 包含UE生成的内联代码

class UUserWidget;  // 前向声明UUserWidget类

UE_DEFINE_GAMEPLAY_TAG_STATIC(TAG_Lyra_ShooterGame_Accolade, "Lyra.ShooterGame.Accolade");  // 定义静态游戏标签：Lyra射击游戏荣誉

static FName NAME_AccoladeRegistryID("Accolades");  // 静态名称：荣誉注册表ID

void ULyraAccoladeHostWidget::NativeConstruct()  // 原生构造方法实现
{
	Super::NativeConstruct();  // 调用父类原生构造

	UGameplayMessageSubsystem& MessageSubsystem = UGameplayMessageSubsystem::Get(this);  // 获取游戏消息子系统实例
	ListenerHandle = MessageSubsystem.RegisterListener(TAG_Lyra_AddNotification_Message, this, &ThisClass::OnNotificationMessage);  // 注册监听器
}

void ULyraAccoladeHostWidget::NativeDestruct()  // 原生析构方法实现
{
	UGameplayMessageSubsystem& MessageSubsystem = UGameplayMessageSubsystem::Get(this);  // 获取游戏消息子系统实例
	MessageSubsystem.UnregisterListener(ListenerHandle);  // 取消注册监听器

	CancelAsyncLoading();  // 取消异步加载

	Super::NativeDestruct();  // 调用父类原生析构
}

void ULyraAccoladeHostWidget::OnNotificationMessage(FGameplayTag Channel, const FLyraNotificationMessage& Notification)  // 通知消息处理方法实现
{
	if (Notification.TargetChannel == TAG_Lyra_ShooterGame_Accolade)  // 如果目标通道是荣誉通道
	{
		// 忽略其他玩家的通知
		if (Notification.TargetPlayer != nullptr)  // 如果目标玩家不为空
		{
			APlayerController* PC = GetOwningPlayer();  // 获取拥有玩家控制器
			if ((PC == nullptr) || (PC->PlayerState != Notification.TargetPlayer))  // 如果玩家控制器为空或玩家状态不匹配
			{
				return;  // 返回
			}
		}

		// 加载此荣誉的数据注册表行
		const int32 NextID = AllocatedSequenceID;  // 获取下一个ID
		++AllocatedSequenceID;  // 递增已分配序列ID

		FDataRegistryId ItemID(NAME_AccoladeRegistryID, Notification.PayloadTag.GetTagName());  // 创建数据注册表ID
		if (!UDataRegistrySubsystem::Get()->AcquireItem(ItemID, FDataRegistryItemAcquiredCallback::CreateUObject(this, &ThisClass::OnRegistryLoadCompleted, NextID)))  // 尝试获取项目
		{
			UE_LOG(LogLyra, Error, TEXT("Failed to find accolade registry for tag %s, accolades will not appear"), *Notification.PayloadTag.GetTagName().ToString());  // 记录错误日志
			--AllocatedSequenceID;  // 递减已分配序列ID（回滚）
		}
	}
}

void ULyraAccoladeHostWidget::OnRegistryLoadCompleted(const FDataRegistryAcquireResult& AccoladeHandle, int32 SequenceID)  // 注册表加载完成处理方法实现
{
	if (const FLyraAccoladeDefinitionRow* AccoladeRow = AccoladeHandle.GetItem<FLyraAccoladeDefinitionRow>())  // 如果成功获取荣誉定义行
	{
		FPendingAccoladeEntry& PendingEntry = PendingAccoladeLoads.AddDefaulted_GetRef();  // 添加默认条目到待加载数组
		PendingEntry.Row = *AccoladeRow;  // 设置行数据
		PendingEntry.SequenceID = SequenceID;  // 设置序列ID

		TArray<FSoftObjectPath> AssetsToLoad;  // 创建要加载的资源路径数组
		AssetsToLoad.Add(AccoladeRow->Sound.ToSoftObjectPath());  // 添加声音资源路径
		AssetsToLoad.Add(AccoladeRow->Icon.ToSoftObjectPath());  // 添加图标资源路径
		AsyncLoad(AssetsToLoad, [this, SequenceID]  // 开始异步加载
		{
			FPendingAccoladeEntry* EntryThatFinishedLoading = PendingAccoladeLoads.FindByPredicate([SequenceID](const FPendingAccoladeEntry& Entry) { return Entry.SequenceID == SequenceID; });  // 查找完成加载的条目
			if (ensure(EntryThatFinishedLoading))  // 确保找到条目
			{
				EntryThatFinishedLoading->Sound = EntryThatFinishedLoading->Row.Sound.Get();  // 获取声音对象
				EntryThatFinishedLoading->Icon = EntryThatFinishedLoading->Row.Icon.Get();  // 获取图标对象
				EntryThatFinishedLoading->bFinishedLoading = true;  // 设置加载完成标志
				ConsiderLoadedAccolades();  // 考虑已加载荣誉
			}
		});
		StartAsyncLoading();  // 开始异步加载
	}
	else  // 如果获取失败
	{
		ensure(false);  // 确保失败（调试断言）
	}
}

void ULyraAccoladeHostWidget::ConsiderLoadedAccolades()  // 考虑已加载荣誉方法实现
{
	int32 PendingIndexToDisplay;  // 待显示索引变量
	do  // 开始循环
	{
		PendingIndexToDisplay = PendingAccoladeLoads.IndexOfByPredicate([DesiredID=NextDisplaySequenceID](const FPendingAccoladeEntry& Entry) { return Entry.bFinishedLoading && Entry.SequenceID == DesiredID; });  // 查找符合显示条件的条目
		if (PendingIndexToDisplay != INDEX_NONE)  // 如果找到有效索引
		{
			FPendingAccoladeEntry Entry = MoveTemp(PendingAccoladeLoads[PendingIndexToDisplay]);  // 移动条目
			PendingAccoladeLoads.RemoveAtSwap(PendingIndexToDisplay);  // 移除原条目

			ProcessLoadedAccolade(Entry);  // 处理已加载荣誉
			++NextDisplaySequenceID;  // 递增下一个显示序列ID
		}
	} while (PendingIndexToDisplay != INDEX_NONE);  // 当找到有效索引时继续循环
}

void ULyraAccoladeHostWidget::ProcessLoadedAccolade(const FPendingAccoladeEntry& Entry)  // 处理已加载荣誉方法实现
{
	if (Entry.Row.LocationTag == LocationName)  // 如果位置标签匹配
	{
		bool bRecreateWidget = PendingAccoladeDisplays.Num() == 0;  // 如果待显示数组为空，则需要重新创建控件
		for (int32 Index = 0; Index < PendingAccoladeDisplays.Num(); )  // 遍历待显示荣誉数组
		{
			if (PendingAccoladeDisplays[Index].Row.AccoladeTags.HasAny(Entry.Row.CancelAccoladesWithTag))  // 如果当前条目标签与取消标签匹配
			{
				if (UUserWidget* OldWidget = PendingAccoladeDisplays[Index].AllocatedWidget)  // 如果已分配控件
				{
					DestroyAccoladeWidget(OldWidget);  // 销毁荣誉控件
					bRecreateWidget = true;  // 设置重新创建控件标志
				}
				PendingAccoladeDisplays.RemoveAt(Index);  // 从数组中移除
			}
			else  // 如果不匹配
			{
				++Index;  // 递增索引
			}
		}

		PendingAccoladeDisplays.Add(Entry);  // 添加条目到待显示数组
		
		if (bRecreateWidget)  // 如果需要重新创建控件
		{
			DisplayNextAccolade();  // 显示下一个荣誉
		}
	}
}

void ULyraAccoladeHostWidget::DisplayNextAccolade()  // 显示下一个荣誉方法实现
{
	if (PendingAccoladeDisplays.Num() > 0)  // 如果待显示数组不为空
	{
		FPendingAccoladeEntry& Entry = PendingAccoladeDisplays[0];  // 获取第一个条目

		GetWorld()->GetTimerManager().SetTimer(NextTimeToReconsiderHandle, this, &ThisClass::PopDisplayedAccolade, Entry.Row.DisplayDuration);  // 设置计时器
		Entry.AllocatedWidget = CreateAccoladeWidget(Entry);  // 创建荣誉控件
	}
}

void ULyraAccoladeHostWidget::PopDisplayedAccolade()  // 弹出显示的荣誉方法实现
{
	if (PendingAccoladeDisplays.Num() > 0)  // 如果待显示数组不为空
	{
		if (UUserWidget* OldWidget = PendingAccoladeDisplays[0].AllocatedWidget)  // 如果已分配控件
		{
			DestroyAccoladeWidget(OldWidget);  // 销毁荣誉控件
		}
		PendingAccoladeDisplays.RemoveAt(0);  // 移除第一个条目
	}

	DisplayNextAccolade();  // 显示下一个荣誉
}